﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data.Sql;
using System.Data;
using System.IO;
using System.Windows.Forms;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord.Framework.Config;
using System.Collections;

namespace Inference
{
    public class LV
    {
        SqlCommand InsertCommand, DeleteCommand, SelectCommand,UpdateCommand,SelectForSlot;
        SqlDataAdapter adapter;
        int FirstFrame, GoalFrame;
        public bool Abort;
        List<int> IDExamples = new List<int>();

        public LV(string ConnectionString)
        {
            SqlConnection Connection = new SqlConnection(ConnectionString);
            Connection.Open();
            InsertCommand = new SqlCommand("",Connection);
            DeleteCommand = new SqlCommand("",Connection);
            SelectCommand = new SqlCommand("",Connection);
            UpdateCommand = new SqlCommand("", Connection);
            SqlConnection connec = new SqlConnection(ConnectionString); connec.Open();
            SelectForSlot = new SqlCommand("", connec);
            adapter = new SqlDataAdapter("",Connection);
            // инициализация
            SelectCommand.CommandText = "Select * from SysTable";
            SqlDataReader rd = SelectCommand.ExecuteReader(); rd.Read();
            FirstFrame = Convert.ToInt32(rd[0]);
            GoalFrame = Convert.ToInt32(rd[1]);
            rd.Close();
            Abort = false;
            // инициализация ActiveRecord
            //ActiveRecordStarter.Initialize(ActiveRecordSectionHandler.Instance, typeof(Log));
            //ActiveRecordStarter.CreateSchema();

            //var props = new Dictionary<string, string>() {
            //{ "connection.driver_class", typeof(NHibernate.Driver.OleDbDriver).AssemblyQualifiedName },
            //{ "dialect", typeof(NHibernate.Dialect.MsSql2005Dialect).AssemblyQualifiedName },
            //{ "connection.provider", typeof(NHibernate.Connection.DriverConnectionProvider).AssemblyQualifiedName },
            //{ "connection.connection_string", "Data Source="+"Provider=SQLOLEDB;"+ Directory.GetCurrentDirectory() + "\\Tale.mdf" },
            //{ "proxyfactory.factory_class", typeof(NHibernate.ByteCode.Castle.ProxyFactoryFactory).AssemblyQualifiedName },
            //{ "show_sql", "true"}
        //};

            //var source = new InPlaceConfigurationSource();
            //source.Add(typeof(ActiveRecordBase), props);
            //ActiveRecordStarter.Initialize(Assembly.GetExecutingAssembly(), source);
            //ActiveRecordStarter.UpdateSchema();

            //InPlaceConfigurationSource source = new InPlaceConfigurationSource();
            //source.Add(typeof(ActiveRecordBase), props);
            //ActiveRecordStarter.Initialize(source, typeof(Log));

    //        IConfigurationSource config = ; 

            //ActiveRecordStarter.Initialize(config, typeof(Log));
                        //ActiveRecordStarter.Initialize(new XmlConfigurationSource("appconfig.xml"), typeof(Log));
            //ActiveRecordStarter.CreateSchema();
        }

        void FixValueSlot(int SlotID,int ValueID,bool reason)
        {
            //// означивание слота
            SelectCommand.CommandText = "Select ValueID from SlotValues where SlotID="+SlotID.ToString();
            if (SelectCommand.ExecuteScalar() == null)
            {
                InsertCommand.Parameters.Clear();
                InsertCommand.CommandText = "Insert into SlotValues values(@value,@slot)";
                InsertCommand.Parameters.AddWithValue("value", ValueID);
                InsertCommand.Parameters.AddWithValue("slot", SlotID);
                InsertCommand.ExecuteNonQuery();
            }
            else
            {
                UpdateCommand.CommandText = "Update SlotValues set ValueID="+ValueID.ToString()+
                    " where SlotID="+SlotID.ToString();
                UpdateCommand.ExecuteNonQuery();
            }
            // добавление записи в лог
            InsertCommand.Parameters.Clear();
            InsertCommand.CommandText = "Insert into Log values(@slot,@reason,@value)";
            InsertCommand.Parameters.AddWithValue("value", ValueID);
            InsertCommand.Parameters.AddWithValue("slot", SlotID);
            InsertCommand.Parameters.AddWithValue("reason", reason);
            InsertCommand.ExecuteNonQuery();
            //Log cs = new Log(SlotID, ValueID, reason);
            //cs.Save();
        }

        string GetRoot(int FrameID)
        {
            DataTable TableFrame = new DataTable();
            do
            {
                TableFrame.Reset();
                adapter.SelectCommand.CommandText = "Select * from Frame where ID=" + FrameID.ToString();
                adapter.Fill(TableFrame);
                if (TableFrame.Rows[0]["Is_a"] != DBNull.Value)
                    FrameID = Convert.ToInt32(TableFrame.Rows[0]["Is_a"]);
                else
                    FrameID = 0;
            }
            while (FrameID!=0);
            return TableFrame.Rows[0]["Name"].ToString();
        }

        List<int> GetParents(int SlotID) // получить родительские слоты данного слота
        {
            List<int> parents = new List<int>();
            DataTable TableFrame = new DataTable(); int FrameID; string SlotName;
            adapter.SelectCommand.CommandText = "Select * from ViewSlotFrame where ID=" + SlotID.ToString();
            adapter.Fill(TableFrame);
            FrameID = Convert.ToInt32(TableFrame.Rows[0]["Is_a"]);
            SlotName = TableFrame.Rows[0]["Name"].ToString();
            do
            {
                TableFrame.Reset();
                adapter.SelectCommand.CommandText = "Select * from ViewSlotFrame where FrameID=" + FrameID.ToString()+" and Name='"+SlotName+"'";
                adapter.Fill(TableFrame);
                if (TableFrame.Rows.Count != 0)
                {
                    if (TableFrame.Rows[0]["Is_a"] != DBNull.Value)
                    {
                        FrameID = Convert.ToInt32(TableFrame.Rows[0]["Is_a"]);
                        parents.Add(Convert.ToInt32(TableFrame.Rows[0]["ID"]));
                    }
                    else
                    {
                        FrameID = 0;
                        parents.Add(Convert.ToInt32(TableFrame.Rows[0]["ID"]));
                    }
                }           
            }
            while (TableFrame.Rows.Count!=0 && FrameID!=0);
            parents.Reverse();
            return parents;
        }


        bool CheckMarker(int FrameID,int SlotID,int IdValue,int mode)
        {
            adapter.SelectCommand.CommandText = "Select * from Fact where SlotID=" + SlotID.ToString();
            DataTable TableMark = new DataTable(); bool test = true;
            adapter.Fill(TableMark);
            foreach (DataRow row in TableMark.Rows)
            {
                int id = Convert.ToInt32(row["id"]);
                int FactValueID = Convert.ToInt32(row["ValueID"]);
                SelectCommand.CommandText = "Select ID from ProductionFact where FactID=" + id.ToString();
                if (SelectCommand.ExecuteScalar() == null) // если маркер
                {
                    string CompID = row["CompSlotID"].ToString();
                    if (mode == 1) // проверка родительских маркеров
                    {
                        SelectCommand.CommandText = "Select Name from Slot where ID="+CompID;
                        string slotname = SelectCommand.ExecuteScalar().ToString();
                        SelectCommand.CommandText = "Select ID from ViewSlotFrame where Name='"+slotname+ "' and FrameID="+FrameID.ToString();
                        CompID = SelectCommand.ExecuteScalar().ToString();
                    }
                    SelectCommand.CommandText = "Select ValueID from SlotValues where SlotID=" + CompID;
                    int val = Convert.ToInt32(SelectCommand.ExecuteScalar());
                    if (val == 0) // если проверяет себя
                        val = IdValue;
                    if ((val == FactValueID) == Convert.ToBoolean(row["Negation"]))
                        test = false;
                }
            }
            return test;
        }

        bool CheckSlotValue(int SlotID, int IdValue)
        {
            adapter.SelectCommand.CommandText = "Select * from Slot where ID=" + SlotID.ToString();
            DataTable TableSlot = new DataTable(); bool test = true;
            adapter.Fill(TableSlot);

            // проверка родительских маркеров
            List<int> parents = GetParents(SlotID);
            foreach (int id in parents)
            {
                if (test)
                    test = CheckMarker(Convert.ToInt32(TableSlot.Rows[0]["FrameID"]), id, IdValue, 1);
            }

            // проверка своего маркера
            if (test)
                test = CheckMarker(0, SlotID, IdValue, 2);

            // проверка по наследованию
            if (Convert.ToInt32(TableSlot.Rows[0]["Domain"]) != 1 && Convert.ToInt32(TableSlot.Rows[0]["Inheritance"]) == 2) // if same
                if (Convert.ToInt32(TableSlot.Rows[0]["DefaultValue"]) != IdValue)
                    test = false;
            return test;
        }


        int CheckProductions(int SlotID)
        {
            DataTable TableRules = new DataTable();
            int IDValue = 0; bool test = true;
            List<int> IdSlots = new List<int>();

            SelectCommand.CommandText = "Select FrameID from Slot where ID=" + SlotID.ToString();
            int FrameID = Convert.ToInt32(SelectCommand.ExecuteScalar());
            SelectCommand.CommandText = "Select Name from Slot where ID=" + SlotID.ToString();
            if (!(GetRoot(FrameID) == "ситуация" && SelectCommand.ExecuteScalar().ToString().ToLower() == "next")) // если не для поля Next
            {
                IdSlots = GetParents(SlotID);
            }
            IdSlots.Add(SlotID);
            
            foreach (int id in IdSlots)
            {
                adapter.SelectCommand.CommandText = "Select * from ViewProductions where SlotID=" + id.ToString();
                adapter.Fill(TableRules);
            }

            foreach (DataRow row in TableRules.Rows)
            {
                int id = Convert.ToInt32(row["SlotID"]);
                int type = Convert.ToInt32(row["Type"]);
                int FactValueID = Convert.ToInt32(row["ValueID"]);
                int CompTarget = Convert.ToInt32(row["CompSlotID"]);
                if (id != SlotID) // если проверяем родительские слоты
                {
                    SelectCommand.CommandText = "Select Domain from Slot where ID=" + row["Place"].ToString();
                    if (SelectCommand.ExecuteScalar().ToString() == "1") // если субфрейм
                    {
                        SelectCommand.CommandText = "Select FrameID from Slot where ID=" + row["SlotID"].ToString();
                        string frame = SelectCommand.ExecuteScalar().ToString();
                        SelectCommand.CommandText = "Select Name from Slot where ID=" + row["Place"].ToString();
                        string place = SelectCommand.ExecuteScalar().ToString();
                        SelectCommand.CommandText = "Select Inheritance from ViewSlotFrame where Name='" + place + "' and FrameID=" + frame;
                        if (SelectCommand.ExecuteScalar().ToString() == "1") // если override
                            continue;
                    }
                    
                    SelectCommand.CommandText = "Select Name from Slot where ID=" + CompTarget.ToString();
                    string slotname = SelectCommand.ExecuteScalar().ToString();
                    SelectCommand.CommandText = "Select ID from ViewSlotFrame where Name='" + slotname + "' and FrameID=" + FrameID.ToString();
                    int target = Convert.ToInt32(SelectCommand.ExecuteScalar());
                    if (target != 0) // если субфрейм
                        CompTarget = target;
                }
                if (test && type == 1) // проверка факта в посылке
                {
                    SelectCommand.CommandText = "Select ValueID from SlotValues where SlotID=" + CompTarget.ToString();
                    int val = Convert.ToInt32(SelectCommand.ExecuteScalar());
                    if ((val == FactValueID) == Convert.ToBoolean(row["Negation"]))
                        test = false;
                    }
                    if (test && type == 2 && (CheckSlotValue(CompTarget, FactValueID))) //  означивание слота
                    {
                        FixValueSlot(CompTarget, FactValueID, true);
                        //return FactValueID;
                        IDValue = FactValueID;
                    }
                    if (type == 3) // обязательное заключение
                    {
                        FixValueSlot(CompTarget, FactValueID, true);
                    }
                    if (type == 2)
                        test = true;
                
                
            }
            return IDValue;
        }


        bool BindingSlot(int SlotID)
        {
            int IdValue = 0;
            if (Abort)
                return false;
            SelectForSlot.CommandText = "Select * from Slot where ID="+SlotID.ToString();
            SqlDataReader rd = SelectForSlot.ExecuteReader(); rd.Read(); 
            if (Convert.ToInt32(rd["Domain"]) != 1)// если не субфрейм
            {
                IdValue=CheckProductions(SlotID);
                if (IdValue==0) // если продукции не сработали/их нет
                {
                    Dictionary<int, string> vv = new Dictionary<int, string>();
                    DataTable TableDomValues = new DataTable();
                    Consult cons = new Consult();
                    List<int> IllegalValues = new List<int>();
                    SelectCommand.CommandText = "Select Name from Frame where ID="+rd["FrameID"].ToString();
                    cons.Text=SelectCommand.ExecuteScalar().ToString()+"/"+rd["Name"].ToString();
                    adapter.SelectCommand.CommandText = "Select * from ViewDomains where DomID=" +
                        Convert.ToInt32(rd["Domain"]) + "order by Number ASC";
                    adapter.Fill(TableDomValues);
                    foreach (DataRow row in TableDomValues.Rows) // составление списка id/значений домена
                    {
                        vv.Add(Convert.ToInt32(row["ID"]), row["Value"].ToString());
                        if (!CheckSlotValue(SlotID, Convert.ToInt32(row["ID"])))
                            IllegalValues.Add(Convert.ToInt32(row["ID"]));
                    }
                    cons.SetQuestion(rd["Question"].ToString(), vv,Convert.ToInt32(rd["DefaultValue"]),IllegalValues);
                    cons.ShowDialog();
                    if (!cons.success) // отменили консультацию
                    {
                        Abort = true;
                        rd.Close();
                        return false;
                    }
                    else
                        IdValue = cons.IdAnswer;
                }
            }
            else // если субфрейм
            {
                rd.Close();
                SelectCommand.CommandText = "Select ID from ViewFrameExample where SlotID=" + SlotID.ToString();
                int id = Convert.ToInt32(SelectCommand.ExecuteScalar());
                if (!IDExamples.Contains(id)) // у данного фрейма-прототипа нет экземпляра
                    return BindingFrame(id);
               
            }
            if (CheckSlotValue(SlotID, IdValue)) //  проверка по маркерам и зад. отсутствия
                FixValueSlot(SlotID, IdValue, true);
            else
            {
                rd.Close();
                return false;
            }
            rd.Close();
            return true;
        }


        bool BindingFrame(int FrameID)
        {
            if (Abort)
                 return false;
            int IdNext=0, NextValue = 0;
            List<int> IDSlots = new List<int>();
            SelectCommand.ExecuteNonQuery();
            DataTable TableFrame = new DataTable(); adapter.SelectCommand.CommandText = "Select * from Slot where FrameID=" + 
                FrameID.ToString()+ "order by Number ASC";
            adapter.Fill(TableFrame);
            foreach (DataRow row in TableFrame.Rows)
            {
                IDSlots.Add(Convert.ToInt32(row["ID"]));
                if ((GetRoot(FrameID).ToLower()=="ситуация") &&  row["Name"].ToString().ToLower() == "next")
                {
                    IdNext = Convert.ToInt32(row["ID"]);
                    if (row["DefaultValue"] != DBNull.Value)
                        NextValue = Convert.ToInt32(row["DefaultValue"]);
                }
                else
                {
                    if (!BindingSlot(Convert.ToInt32(row["ID"])))
                    {
                        // фрейм не привязался
                        foreach (int id in IDSlots)
                        {
                            DeleteCommand.CommandText = "Delete from SlotValues where SlotID=" + id.ToString();
                            DeleteCommand.ExecuteNonQuery();
                        }
                        // идем куда-то ...
                        return false;
                    }
                }
            }
            //фрейм привязался
                if (GetRoot(FrameID).ToLower()=="ситуация") // если это фрейм-ситуация
            {
                int n = CheckProductions(IdNext);
                if (n != 0)
                    NextValue = n;
            }
            IDExamples.Add(FrameID);
            if (FrameID == GoalFrame)
                MessageBox.Show("Означили целевой фрейм");
            else
                if (NextValue!=0)
            {               
                SelectCommand.CommandText = "Select ID from ViewFrameExample where ValueID=" + NextValue.ToString();                
                BindingFrame(Convert.ToInt32(SelectCommand.ExecuteScalar()));
            }
            return true;
        }

        public void StartConclusion()
        {
            // чистка лога
            DeleteCommand.CommandText = "Delete from Log where SlotID>0";
            DeleteCommand.ExecuteNonQuery();
             //удаление фреймов-экземпляров
            DeleteCommand.CommandText = "Delete from SlotValues where SlotID>0";
            DeleteCommand.ExecuteNonQuery();

            BindingFrame(FirstFrame);
            
        }


    }
}
